﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using King.Engine.GameObjects;
using Microsoft.Xna.Framework;
using King.Engine.Core;
using Microsoft.Xna.Framework.Input;
using BreacherCreature.Components.Lights;
using BreacherCreature.Components;
using King.Engine.Components;

namespace BreacherCreature.GameObjects
{
    public class Creature : Character
    {

        #region Fields

        private Human _breachedHuman;
        Timer _possessionTimer;


        #endregion


        #region Constants

        private const int SIZE = 256;
        private static Rectangle COLLISION_BOUNDS = new Rectangle(90, 50, 70, 180);

        private static readonly Vector2 UP = new Vector2(0, -1);
        private static readonly Vector2 RIGHT = new Vector2(1, 0);

        #endregion


        #region Properties

        public int Speed;
        public CreatureState State;
        
        #endregion


        #region Constructors

        static Creature()
        {
            Input<CharacterControls>.Initialize(new Dictionary<CharacterControls,Keys>()
            {
                {CharacterControls.Left, Keys.A},
                {CharacterControls.Right, Keys.D},
                {CharacterControls.Down, Keys.S},
                {CharacterControls.Up, Keys.W},
                {CharacterControls.Breach, Keys.Space}
            });

        }

        public Creature(Point spawn)
            : base(AnimationSets.Creature, CharacterAnimations.Idle)
        {
            this.CollisionBounds = COLLISION_BOUNDS;
            Speed = 200;
            State = CreatureState.Normal;

            _possessionTimer = new Timer(0, new EndTimerCallback(Unbreach), false);
            Bounds.Location = spawn;
            Bounds.Width = SIZE;
            Bounds.Height = SIZE;

            AddComponent(_possessionTimer);
            AddComponent<CollisionPusher<Wall>>();
        }

        #endregion


        #region Public Methods

        public void OnLightEnter()
        {
            ColorOverlay = Color.White;
        }

        #endregion


        #region Protected Methods

        protected override void UpdateBeforeComponents(GameTime gameTime)
        {
            var controlsPressed = Input<CharacterControls>.ControlsPressed();

            foreach (var control in controlsPressed)
            {
                switch (control)
                {
                    case CharacterControls.Up:
                        Move(UP, this.Speed, gameTime);
                        break;

                    case CharacterControls.Down:
                        Move(-UP, this.Speed, gameTime);
                        break;

                    case CharacterControls.Right:
                        Move(RIGHT, this.Speed, gameTime);
                        break;

                    case CharacterControls.Left:
                        Move(-RIGHT, this.Speed, gameTime);
                        break;
                }
            }

            if (Input<CharacterControls>.ControlTapped(CharacterControls.Breach))
            {
                TryBreach();
            }

            ColorOverlay = Color.Gray;

            base.UpdateBeforeComponents(gameTime);
        }

        protected override void OnMove()
        {
            Screen.CenterAt(this);
        }

        #endregion


        #region Private Methods

        private void TryBreach()
        {
            Activity activity = ActivityManager.CurrentActivity;

            if (State == CreatureState.Normal)
            {
                var humans = activity.GetObjectsOfType<Human>();

                Human collidedHuman = humans.FirstOrDefault(h => this.CollidesWith(h) && h.PossessionSeconds > 0);

                if (collidedHuman != null)
                {
                    _breachedHuman = collidedHuman;
                    Animations = _breachedHuman.Animations;
                    SetAnimation(CharacterAnimations.Idle);
                    this.Location = _breachedHuman.Location;
                    State = CreatureState.Breached;

                    LightCone original = collidedHuman.GetComponents<LightCone>().FirstOrDefault();

                    if (original != null)
                    {
                        AddComponent(original);
                        original.FlickerOff();
                    }
                    activity.RemoveGameObject(collidedHuman);
                    RemoveComponents<Timer>();
                    _possessionTimer = new Timer(collidedHuman.PossessionSeconds, new EndTimerCallback(Unbreach));
                    AddComponent(_possessionTimer);
                }
            }
            else if (State == CreatureState.Breached)
            {
                var collidedSwitch = activity.GetObjectsOfType<LightSwitch>().FirstOrDefault(s => this.CollidesWith(s));

                if (collidedSwitch != null)
                {
                    collidedSwitch.SwitchToggle();
                }
            }
        }

        private void Unbreach()
        {
            int pixelPushOffset = 3;
            Activity activity = ActivityManager.CurrentActivity;
            _breachedHuman.Bounds.X = CollisionBounds.Right + pixelPushOffset;
            _breachedHuman.Bounds.Y = CollisionBounds.Top + pixelPushOffset;
            _breachedHuman.PossessionSeconds *= _possessionTimer.PercentRemaining;
            activity.AddGameObject(_breachedHuman);
            _breachedHuman = null;
            Animations = AnimationSets.Creature;
            SetAnimation(CharacterAnimations.Idle);
            _possessionTimer.Running = false;
            CollisionBounds = COLLISION_BOUNDS;
            State = CreatureState.Normal;
        }

        #endregion

    }

    public enum CharacterControls
    {
        Up,
        Down,
        Left,
        Right,
        Breach
    }

    public enum CreatureState
    {
        Normal,
        Breached
    }

}
